//==============================================================================
// Regex.cc
// ----------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
// $Id: Regex.cc,v 1.1 2000/01/31 21:15:57 kdurbin Exp $
//------------------------------------------------------------------------------
// $Log: Regex.cc,v $
// Revision 1.1  2000/01/31 21:15:57  kdurbin
// Initial revision
//
//   
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#include "Regex.hh"

#if 0
//---------------------------------------------------------------------------
// * Regex
//---------------------------------------------------------------------------
// Converts a character literal to a string and calls string constructor.
Regex::Regex(const char* pPat)
{
  string a = pPat;
  Regex::Regex(a);
}
#endif

//---------------------------------------------------------------------------
// * Regex
//---------------------------------------------------------------------------
// 
Regex::Regex(string &pat)
{
	mbFirstTime = true;
	mPattern = pat;
	re_set_syntax((reg_syntax_t)RE_SYNTAX_EGREP);
	Compile();
}

//---------------------------------------------------------------------------
// * ~Regex
//---------------------------------------------------------------------------
// 
Regex::~Regex()
{
	regfree(&mPatBuf);
}


//---------------------------------------------------------------------------
// * Compile
//---------------------------------------------------------------------------
// 
void
Regex::Compile()
{
	// Clear old buffers if not the first time.  regfree does it's 
	// own checking for NULL so the check here for mbFirstTime is 
	// somewhat redundant. 
	if (!mbFirstTime) regfree(&mPatBuf);

	mPatBuf.translate = 0;
	mPatBuf.fastmap = mFastMap;
	mPatBuf.buffer = 0;
	mPatBuf.allocated=0;
	
	char *compileError;
	compileError= re_compile_pattern((const char*)mPattern.c_str(),
												(int) mPattern.size(),
												(struct re_pattern_buffer*)&mPatBuf);

	// This check seems to be necessary when using ObjectSpace STL
	// Assigning a null pointer to a string throws an exception.
	if (compileError !=NULL) mErrString = compileError;

	mbFirstTime = false;
}

//---------------------------------------------------------------------------
// * Find
//---------------------------------------------------------------------------
// 
int
Regex::Find(string &target)
{
	return(Find(0,target));
}
  
//---------------------------------------------------------------------------
// * Find
//---------------------------------------------------------------------------
// Uses GNU re_search with a fastmap. 
int
Regex::Find(int offset,string &target)
{
	if (offset >= target.size()) return(-1);

	// match returns the size of the match, not the 
	// location
	int idx;
	int range = target.size()-offset;
	idx = re_search((struct re_pattern_buffer*)&mPatBuf,
						(const char*)target.c_str(),
						(const int)target.size(),
						(const int)offset,(const int)target.size(),
						(struct re_registers*)0);

	// compute the location from the offset and size and return
	return(idx);
}

	
//---------------------------------------------------------------------------
// * FindEndWithMatch
//---------------------------------------------------------------------------
// 
int
Regex::FindEndWithMatch(string &target)
{
	return(FindEndWithMatch(0,target));
}
  
//---------------------------------------------------------------------------
// * FindEndWithMatch
//---------------------------------------------------------------------------
// Uses GNU re_match to locate the end of a match to a re.  This matches the 
// entire string against the regular expression.  You can simulate a search 
// by putting the equivalent of (anychar)* at the beginning of your 
// search string.  This should be faster than using re_search since
// the regular expression examines each character in the target exactly 
// once.  The main drawback is no obvious way to locate the start of the 
// part of the pattern you are really interested in.  
//
int
Regex::FindEndWithMatch(int offset,string &target)
{
	if (offset >= target.size()) return(-1);

	// match returns the size of the match, not the 
	// location
	int msize;
	msize = re_match((struct re_pattern_buffer*)&mPatBuf,
						(const char*)target.c_str(),
						(const int)target.size(),
						(const int)offset,
						(struct re_registers*)0);

	// compute the location from the offset and size and return
	return(msize+offset-1);
}

//---------------------------------------------------------------------------
// * Match
//---------------------------------------------------------------------------
// 
bool
Regex::Match(string &target){
	return(Match(0,target));
}

//---------------------------------------------------------------------------
// * Match
//---------------------------------------------------------------------------
// 
bool
Regex::Match(int offset,string &target)
{
	if (offset >= target.size())return(false);
	
	int loc = Find(offset,target);
	if (loc>=0){
		return(true);
	}else{
		return(false);
	}
}




